Release 10.1A: OpenEdge Development:
Progress 4GL Handbook


Cleaning up dynamically allocated memory

When you run a procedure with only static objects, these objects come and go with the procedure that defines them. Because Progress can see the individual DEFINE statements for the objects, it knows when to create them, when they go out of scope, and when to delete them. You don’t have to worry about deleting them because Progress does it automatically for you.

The same is true, incidentally, of handles for static objects. When you store the handle of a static object in a HANDLE variable, that value is just a pointer to the object. It doesn’t extend or affect the scope of the static object in any way. The variable itself, because it’s defined statically, is also deleted by Progress when its procedure goes out of scope.

When you create dynamic objects, however, Progress cannot control their scope or their lifetime. If you create a dynamic object inside a loop, Progress might have no way of knowing at compile time how many of those objects the procedure will create. If you pass the handle of an object as a parameter to another procedure, Progress has no way of knowing at compile time where the handle came from, what it will be used for, or when the object it represents can safely be deleted. This is why you are responsible for taking care of this.

To see a dramatic example of the importance of memory management:

  1. Open the h-DeleteObject.p procedure used earlier and comment out the statements that delete the dynamic query and buffer objects at the end of the loop:
  2. /* h-DeleteObject.p */ 
    DEFINE VARIABLE hQuery AS HANDLE      NO-UNDO. 
    DEFINE VARIABLE hBuffer AS HANDLE     NO-UNDO. 
    DEFINE VARIABLE iCount AS INTEGER     NO-UNDO. 
         
        ETIME(TRUE). 
        DO iCount = 1 TO 100: 
            FOR EACH _file WHERE _file-num > 0 AND _file-num  32000: 
                CREATE QUERY hQuery. 
                 CREATE BUFFER hBuffer FOR TABLE _file._file-name. 
                hQuery:SET-BUFFERS(hBuffer). 
                hQuery:QUERY-PREPARE("FOR EACH " + _file._file-name). 
                hQuery:QUERY-OPEN(). 
                hQuery:GET-FIRST(). 
                hQuery:QUERY-CLOSE(). 
    /*             DELETE OBJECT hQuery.  */ 
    /*             DELETE OBJECT hBuffer. */ 
           END. 
        END. 
      MESSAGE "100 iterations took " ETIME "milliseconds" VIEW-AS ALERT-BOX. 
    

  3. Bring up the Windows Task Manager, select the Processes tab, and find the running executable called prowin32.exe:
  4. Run the procedure, and watch the memory go:
  5. After just 100 iterations of this loop, which only created two dynamic objects, you’ve lost six megabytes of memory! Not only that, but even though you removed two key statements from the procedure, it ran about four times slower:

    The reason for this is that all that extra memory allocation is getting in the way of your procedure running efficiently. So you pay a heavy price all the way around.

    Use the DELETE OBJECT statement to get rid of the memory for any dynamic object, regardless of its type. To summarize, you use a CREATE QUERY statement to create a dynamic query, a CREATE BUTTON statement to create a dynamic button, and a CREATE BROWSE statement to create a dynamic browse, but you use the DELETE OBJECT statement to clean up each of them.

    You must also remember to clean up persistent procedures when you’re done with them. Every time you execute a statement of the RUN procedure-name PERSISTENT SET proc-handle form, you are also allocating memory for the procedure and all its contents. You need to delete the procedure, when you’re done with it, with the DELETE PROCEDURE statement.


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095